In part one the menu lived inside the code, which is fine right up until a client emails at eleven at night asking you to rename Work to Portfolio, and you realize that changing one word means recompiling an entire SWF. XML fixes that permanently. The menu becomes a plain text file a human can edit without ever opening Flash, and the code stops caring how many items there are or what they say.
The menu, as a text file
First the data. This is menu.xml, sitting next to your SWF, editable by anyone with a text editor and no fear.
<?xml version="1.0" encoding="utf-8"?>
<menu>
<item label="Home" url="index.html" />
<item label="Work" url="work.html" />
<item label="About" url="about.html" />
<item label="Contact" url="contact.html" />
</menu>
The code that reads it
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
public class XMLMenu extends Sprite {
private var loader:URLLoader;
public function XMLMenu() {
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, onLoaded);
loader.load(new URLRequest("menu.xml"));
}
private function onLoaded(event:Event):void {
var data:XML = new XML(loader.data);
var format:TextFormat = new TextFormat();
format.size = 18;
var i:int = 0;
for each (var item:XML in data.item) {
var button:Sprite = new Sprite();
button.graphics.beginFill(0x1a1a1a);
button.graphics.drawRect(0, 0, 160, 36);
button.graphics.endFill();
button.y = i * 44;
button.buttonMode = true;
button.mouseChildren = false;
button.name = item.@url;
var label:TextField = new TextField();
label.defaultTextFormat = format;
label.textColor = 0xffffff;
label.text = item.@label;
label.x = 12;
label.y = 8;
label.selectable = false;
button.addChild(label);
button.addEventListener(MouseEvent.CLICK, onSelect);
addChild(button);
i++;
}
}
private function onSelect(event:MouseEvent):void {
trace("Navigate to: " + event.currentTarget.name);
}
}
}
Two new characters join the cast. URLLoader fetches the file, and it does it asynchronously, which is a formal way of saying the load does not block and you do not get to use the data until it arrives. That is what the Event.COMPLETE listener is for. You ask for the file, you go about your day, and onLoaded gets tapped on the shoulder when the bytes show up.
The real magic is E4X, which is XML parsing that pretends to be object access and mostly gets away with it. data.item gives you every item node. for each walks them. And item.@label reads the label attribute with an at sign, which is either elegant or cursed depending on your mood, but you will admit it beats forty lines of DOM traversal. Notice mouseChildren is still false, because the physics of clicking did not change just because the data moved out of the file.
Now the menu is data. Add an item to the XML, reload, and it appears with no compile step and no ceremony. The designer edits a text file and feels quietly powerful, the developer never gets the eleven pm email, and everyone wins, which as you know almost never happens in software.